package com.client.rule.triple;

import java.util.Map;
import java.util.Vector;

import com.shared.rule.TypeComplexTriple;
import com.shared.rule.TypeDataRule;
import com.shared.rule.TypeOperator;



public class TripleParser {

	private static String OR = "OR";
	private static String AND = "AND";
	private static String NOT = "NOT";
	
	private static String LT = "<";
	private static String GT = ">";
	private static String DIFF = "<>";
	
	
	private static Vector<String> split(String s){
		char[] inputChar = s.toCharArray();
		Vector<String> v = new Vector<String>();
		StringBuilder temp = new StringBuilder();
		int countParenthesis = 0;		
		for(char c:inputChar){
		    if(c=='('){
		    	countParenthesis++;
		    	if(countParenthesis==1){
		    		v.add(temp.toString());		    		
			        temp = new StringBuilder();
			    }else{temp.append(c);}	        
		        
		    }
		    else if(c==',' && countParenthesis==1){
		        if(!temp.toString().equals(",") && !temp.toString().equals("")) v.add(temp.toString());
		        temp = new StringBuilder();  
		    }
		    else if(c==')' ){
		    	countParenthesis--;
		    	if(countParenthesis==0){
		    		if(!temp.toString().equals("")) v.add(temp.toString());
		    		
		    		temp = new StringBuilder();
		    	}else{temp.append(c);}
		        
		    }
		    else temp.append(c);
		}
		if(!temp.toString().equals("")) v.add(temp.toString());
		return v;
	}
	
	
	
	private static boolean isComplexPrefix(String s){		
		return OR.equals(s) || AND.equals(s) || NOT.equals(s) ;
	}
	
	
	
	public static UiTriple parse(String s,Map<String, TypeDataRule> data) throws IllegalArgumentException{		
		
		s = removeSpaces(s);
		if(s.isEmpty()) throw new IllegalArgumentException("Erreur \n: Une condition est vide");
		
		Vector<String> splited = split(s);
		
		UiTriple triple;
		if(isComplexPrefix(splited.get(0))){
			triple=new UiComplexTriple(splited.get(0),TypeComplexTriple.valueOf(splited.get(0)));			
			for(int i=1;i<splited.size();i++){
				((UiComplexTriple) triple).add(parse(splited.get(i),data));
			}
		}else{	
			String op = getOperator(splited.get(0));
			
			String label1 = getLeft(splited.get(0));
			String label2 = getRight(splited.get(0));
			
			if(op.isEmpty()) throw new IllegalArgumentException("Erreur :\n"+
					"la condition n'a pas d'operateur de comparaison : \n"+
					splited.get(0));
			
			TypeDataRule type1 = data.get(label1);
			TypeDataRule type2 = data.get(label2);
			if(type1==null){
				if(type2==null)	throw new IllegalArgumentException("Erreur : \n"+
						label1+" et "+label2+" n'ont pas de type connu");	
				checkType(label1, label2, type2);
				triple=new UiSimpleTriple(label1,label2,TypeOperator.getTypeOperator(op,type2));	
			}else{
				if(type2==null){
					checkType(label2, label1, type1);
					triple=new UiSimpleTriple(label1,label2,TypeOperator.getTypeOperator(op,type1));	
				}else{
					if(type2!=type1) throw new IllegalArgumentException("Erreur :\n"+
							label1+" et "+label2+" ne sont pas du meme type");		
					triple=new UiSimpleTriple(label1,label2,TypeOperator.getTypeOperator(op,type1));	
				}
			}
		}		 
		
		return triple;
	}
	
	public static String getOperator(String s){
		if(s.indexOf("=")!= -1) return "=";
		if(s.indexOf(DIFF)!= -1) return DIFF;
		if(s.indexOf(LT)!= -1) return LT;
		if(s.indexOf(GT)!= -1) return GT;
		else return "";
	}
	
	public static String getLeft(String s){
		return s.substring(0,s.indexOf(getOperator(s)));
	}
	
	public static String getRight(String s){		
		return s.substring(s.indexOf(getOperator(s))+getOperator(s).length(),s.length());
	}
	
		
	public static String removeSpaces(String s) {
		char[] inputChar = s.toCharArray();
		StringBuilder temp = new StringBuilder();
		for(char c : inputChar){			
			if(!Character.isSpace(c)){				
				temp.append(c);
			}
		}
		return temp.toString();
	}
	
	private static void checkType(String s,String autre,TypeDataRule type) throws IllegalArgumentException{
		switch (type) {
		case NUMERIC:
			try{
				Double.parseDouble(s);
			}catch (NumberFormatException e) {
				throw new IllegalArgumentException("Erreur pour "+autre+" attendu : Numérique, recu :"+s);
			}
			break;
		case BOOLEAN:
			if(!s.equals("true") && !s.equals("false"))
				throw new IllegalArgumentException("Erreur pour "+autre+" attendu : (true,false), recu :"+s);			
			break;
		default:
			break;
		}
	}
	
		
	public static String changeForbiddenChar(String s){		
		if(s.indexOf(DIFF)!= -1){
			return s.substring(0, s.indexOf(DIFF))+"&lt;&gt;"+s.substring(s.indexOf(DIFF)+2,s.length());
		}
		if(s.indexOf(LT)!= -1){
			return s.substring(0, s.indexOf(LT))+"&lt;"+s.substring(s.indexOf(LT)+1,s.length());
		}
		if(s.indexOf(GT)!= -1){
			return s.substring(0, s.indexOf(GT))+"&gt;"+s.substring(s.indexOf(GT)+1,s.length());
		}
		return s;
	}
	
	public static String replaceForbiddenChar(String s){		
		if(s.indexOf("&lt;&gt;")!= -1){
			return s.substring(0, s.indexOf("&lt;&gt;"))+DIFF+s.substring(s.indexOf("&lt;&gt;")+8,s.length());
		}
		if(s.indexOf("&lt;")!= -1){
			return s.substring(0, s.indexOf("&lt;"))+LT+s.substring(s.indexOf("&lt;")+4,s.length());
		}
		if(s.indexOf("&gt;")!= -1){
			return s.substring(0, s.indexOf("&gt;"))+GT+s.substring(s.indexOf("&gt;")+4,s.length());
		}
		return s;
	}
}
